home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Magnum One
/
Magnum One (Mid-American Digital) (Disc Manufacturing).iso
/
d20
/
msgq160s.arc
/
MSGLINK.C
< prev
next >
Wrap
Text File
|
1991-10-26
|
15KB
|
594 lines
/*
* MSGLINK.C - Link QuickBBS reply chains using EID lines
*
* Msged/Q message editor for QuickBBS Copyright 1990 by P.J. Muller
*
* This file is not used by Msged/Q
*/
#define SHOWMEM
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef SHOWMEM
#include <alloc.h>
#endif
#define MAIN
#include "msglink.h"
typedef BYTE BITSET[32]; /* [0..255] */
#define clearset(a) memset(a,0,sizeof(BITSET));
#define setbit(b,a) a[(b)/8] |= (1 << ((b) % 8))
#define isset(b,a) (a[(b)/8] & (1 << ((b) % 8)))
typedef struct {
int num; /* board number */
char *name; /* board name */
} BOARD;
static BOOLEAN readeid(MSGHEADER *hdr, ID *EID, ID *RID);
static int readlinks(BITSET boards, MSGDATA ***link);
#ifdef DEBUG
static void showlist(MSGDATA **link, int len);
#endif
static void linklist(MSGDATA **link, int LEN);
static int sort_st_crc(MSGDATA **a, MSGDATA **b);
static char *prepsubj(char *s);
static void dosubjs(MSGDATA **link, int len);
static int sort_num(MSGDATA **a, MSGDATA **b);
static void writelinks(MSGDATA **link,int len);
static void parseargs(int argc,char *argv[],BITSET useboard,BOOLEAN *subj,BOOLEAN *eid);
static BOARD **readareas(char *fname);
static BOOLEAN readtosslog(char *tosslog, BOARD **board, BITSET useboard);
static BOOLEAN subjlink; /* link Subj lines */
static BOOLEAN eidlink; /* link EID lines */
#define fatal(s) { fprintf(stderr,"\nFatal: %s\n",s); exit(1); }
int main(int argc, char *argv[])
{
MSGDATA **link;
int len;
#ifdef SHOWMEM
long memory;
#endif
BITSET useboard;
fprintf(stderr,"EID message linking Version 1.1 Copyright 1991 P.J. Muller 5:7102/11\n\n");
parseargs(argc,argv,useboard,&subjlink,&eidlink);
if (!openmsgbase())
fatal("Could not open message base");
#ifdef SHOWMEM
memory = coreleft();
#endif
len = readlinks(useboard, &link);
if (len != 0) {
#ifdef SHOWMEM
fprintf(stderr,"\n\tUsing %dk memory",(int)((memory-coreleft())/1024));
#endif
fprintf(stderr,"\n\nLinking messages...");
if (subjlink)
dosubjs(link,len);
linklist(link,len); /* after this link will be sortde by number */
fprintf(stderr,"\n\nWriting new links...");
writelinks(link,len);
fprintf(stderr,"\n\tDone\n");
} else {
fprintf(stderr,"Less than two messages selected -> nothing to do!\n");
} /* else */
if (!closemsgbase())
fatal("Could not close message base");
return(0);
} /* main */
/*
* Compare function for sort by time/date stamp then CRC then board number
*/
static int sort_st_crc(MSGDATA **a, MSGDATA **b)
{
int diff;
if ((*a)->EID.st < (*b)->EID.st)
return(-1); /* a < b */
if ((*a)->EID.st > (*b)->EID.st)
return(1); /* a > b */
/* time/date stamps are equal */
/* can do this trick because crc is an int */
diff = (*a)->EID.crc - (*b)->EID.crc;
if (diff != 0)
return(diff);
/* cast to int for trick */
return((int)(*a)->area - (int)(*b)->area);
} /* sort_st_crc */
/*
* Compare function for sort by area then subj then number
*/
static int sort_subj(MSGDATA **a, MSGDATA **b)
{
int diff;
diff = (int)(*a)->area - (int)(*b)->area;
if (diff != 0)
return(diff);
diff = strcmp((*a)->subj,(*b)->subj);
if (diff != 0)
return(diff);
return((*a)->no - (*b)->no);
#ifdef ZAPTHISOUT
if ((*a)->EID.st < (*b)->EID.st)
return(-1); /* a < b */
if ((*a)->EID.st > (*b)->EID.st)
return(1); /* a > b */
return(0);
#endif
} /* sort_subj */
/*
* Compare function for sort by 'no'
*/
static int sort_num(MSGDATA **a, MSGDATA **b)
{
return((*a)->no - (*b)->no);
} /* sort_num */
/*
* Display the list of messages
*/
#ifdef DEBUG
static void showlist(MSGDATA **link, int len)
{
printf("\n");
while (len--) {
printf("%4d %04x %08lx %04x %08lx %4d %4d %4d %4d %s\n", (*link)->no,
(*link)->EID.crc,(*link)->EID.st,
(*link)->x.RID.crc,(*link)->x.RID.st,
(*link)->up,(*link)->down,
(*link)->oup,(*link)->odown,
(*link)->subj == NULL ? "" : (*link)->subj);
link++;
} /* while */
printf("\n");
} /* showlist */
#endif
/*
* Link the messages
*/
static void linklist(MSGDATA **numidx, int LEN)
{
int c;
size_t len = LEN; /* lfind wants a pointer to size_t */
MSGDATA key,*keyptr,**dateidx;
MSGDATA **found;
fprintf(stderr,"\n\tSorting EID's");
dateidx = calloc(len,sizeof(MSGDATA *)); /* make another index */
if (dateidx == NULL)
fatal("Out of memory.");
memcpy(dateidx,numidx,len*sizeof(MSGDATA *));
qsort(dateidx,len,sizeof(MSGDATA *),sort_st_crc);
qsort(numidx,len,sizeof(MSGDATA *),sort_num);
#ifdef DEBUG
/*showlist(numidx,len);*/
#endif
fprintf(stderr,"\n\tLinking EID's");
memset(&key,0,sizeof(key));
keyptr = &key;
for (c = 0; c < len; c++) {
if (numidx[c]->x.RID.st == 0)
continue; /* no RID */
key.area = numidx[c]->area;
key.EID = numidx[c]->x.RID;
found = bsearch(&keyptr,dateidx,len,sizeof(dateidx[0]),sort_st_crc);
/* step to end of reply list */
while ((found != NULL) && (key.no = (*found)->up) != 0)
found = bsearch(&keyptr,numidx,len,sizeof(numidx[0]),sort_num);
if (found != NULL) { /* add link */
if ((*found)->no < numidx[c]->no) { /* avoid endless loops */
(*found)->up = numidx[c]->no;
numidx[c]->down = (*found)->no;
} /* if */
} /* if */
} /* for */
#ifdef DEBUG
/* showlist(numidx,len); */
#endif
} /* linklist */
/*
* Link the Subj lines
*/
static void dosubjs(MSGDATA **link, int len)
{
MSGDATA **step, **base=link;
int c;
fprintf(stderr,"\n\tSorting Subjects");
qsort(link,len,sizeof(link[0]),sort_subj);
fprintf(stderr,"\n\tLinking Subjects");
c = len;
while (c > 1) {
step = base+1; /* Subj after current */
if ((*base)->EID.st != 0) /* skip empty EID's */
while ((--c > 0) && ((*base)->area == (*step)->area) &&
(strcmp((*base)->subj,(*step)->subj)) == 0) {
(*step)->x.RID = (*base)->EID; /* create RID */
++step;
} /* while */
base = step; /* skip same subj's */
} /* while */
#ifdef DEBUG
/* showlist(link,len); */
#endif
#ifndef DEBUG /* free()'ing not really necessary */
for (c = 0, step = link; c < len; c++, step++) {
free((*step)->subj);
(*step)->subj = NULL;
} /* for */
#endif
} /* dosubjs */
/*
* Read all the links of a message base
* Return an array of pointers to MSGDATA instances
*/
static int readlinks(BITSET boards, MSGDATA ***link)
{
MSGHEADER header;
MSGDATA *temp;
int board, idx, len, maxlen;
ID EID,RID;
maxlen = 0;
for (idx=0; idx < filemsgs; idx++) {
if ((msgidx[idx].msgnum == -1) || (msgidx[idx].board == 0))
continue; /* deleted message */
board = msgidx[idx].board; /* board number */
if (!isset(board-1,boards))
continue; /* we are not interested */
maxlen++; /* one more */
} /* for */
if (maxlen < 2) return 0;
fprintf(stderr,"Reading %d messages...",maxlen);
*link = calloc(maxlen,sizeof(MSGDATA *)); /* allocate array */
if (*link == NULL)
fatal("Out of memory.");
/*
* Now read the message headers
*/
fprintf(stderr,"\n\tReading Headers");
len = 0; /* will now count real length */
for (idx=0; idx < filemsgs; idx++) {
if ((msgidx[idx].msgnum == -1) || (msgidx[idx].board == 0))
continue; /* deleted message */
board = msgidx[idx].board; /* board number */
if (!isset(board-1,boards))
continue; /* we are not interested */
if (readheader(msgidx[idx].msgnum,&header)) {
if (header.numrecs == 0) continue;
if ((temp = calloc(1,sizeof(MSGDATA))) == NULL)
fatal("Out of memory.");
temp->no = header.msgnum;
temp->area = board;
temp->oup = header.up;
temp->odown = header.reply;
temp->EID.st = dostime(header.posttime,header.postdate,TRUE);
temp->EID.crc = rand();
temp->x.startrec = header.startrec;
if (subjlink)
temp->subj = prepsubj(header.subj);
(*link)[len++] = temp; /* pointer to last */
} /* if */
} /* for */
/*
* By this time all messages will have a fake EID in memory
* Now start reading real EID's and reply EID's if required
*/
if (eidlink) {
fprintf(stderr,"\n\tReading EID's");
memset(&header,0,sizeof(header));
for (idx=0; idx < len; idx++) {
temp = (*link)[idx];
header.numrecs = 1; /* read only 255 chars */
header.startrec = temp->x.startrec; /* knows about the insides */
header.msgnum = temp->no; /* of readtext() */
if (!readeid(&header,&EID,&RID))
fatal("Error while reading message text (memory?)");
if (EID.st != 0) { /* found and EID, override default */
temp->EID = EID;
temp->x.RID = RID;
} /* if */
} /* for */
} /* if */
return(len);
} /* readlinks */
static BOOLEAN readeid(MSGHEADER *hdr, ID *EID, ID *RID)
{
char *text,*eid;
int count;
memset(EID,0,sizeof(ID));
memset(RID,0,sizeof(ID));
if ((text = readtext(hdr)) == NULL)
return(FALSE);
eid = strstr(text,"\01EID:");
if (eid != NULL)
count = sscanf(eid, "\01EID: %x %X %x %X\r", &EID->crc, &EID->st, &RID->crc, &RID->st);
switch (count) { /* check for partial match */
case 1:
memset(EID,0,sizeof(ID));
break;
case 3:
memset(RID,0,sizeof(ID));
break;
} /* switch */
free(text);
return(TRUE);
} /* readeid */
/*
* Write all the new links of a message base
*/
static void writelinks(MSGDATA **link,int len)
{
MSGHEADER header;
MSGDATA **step;
int c;
#ifdef DEBUG
/* showlist(link,len); */
#endif
fprintf(stderr,"\n\tWriting links");
for (c = 0, step = link; c < len; c++, step++) {
if (((*step)->up == (*step)->oup) && ((*step)->down == (*step)->odown))
continue; /* no change to links */
if (!readheader((*step)->no,&header))
continue; /* can't read */
header.up = (*step)->up;
header.reply = (*step)->down;
writeheader(&header);
} /* for */
} /* writelinks */
/*
* Prepare a Subj line and return a malloc'ed string
*/
static char *prepsubj(char *s)
{
char subj[73];
while (strnicmp(s,"Re: ",4) == 0)
s += 4; /* skip leading RE:'s */
strcpy(subj,s);
subj[25] = EOS; /* at most 25 characters */
strupr(subj);
return(strdup(subj));
} /* prepsubj */
/*
* Parse the command line
*/
static void parseargs(int argc, char *argv[], BITSET useboard, BOOLEAN *subj, BOOLEAN *eid)
{
char *toss = NULL;
BOOLEAN dirty = FALSE;
clearset(useboard);
if (argc < 2) {
fprintf(stderr,"Usage: MsgLink [-s] [-e] [-llogname] [board] [board1-board2] ...\n");
fprintf(stderr,"\nLinks QuickBBS messages in numerical order using ^aEID and Subject lines.\n");
fprintf(stderr,"\n\t-e\tDisable ^aEID kludge line linking\n");
fprintf(stderr, "\t-s\tDisable Subject line linking\n");
fprintf(stderr, "\t-l\tSpecify a tossed board log file\n");
fprintf(stderr,"\nE.g.:\tMsgLink 1-2 3-6 10 Links messages in boards 1-6 and 10\n");
fprintf(stderr, "\tMsgLink -s 1-200 Links all messages using only EID's.\n");
fprintf(stderr, "\tMsgLink -e 3 132 Links messages in board 3 & 132 using only Subj.\n");
fprintf(stderr, "\tMsgLink -lQECHO.TMP Links messages in boards listed in QECHO.TMP\n");
exit(1);
} /* if */
*subj = TRUE;
*eid = TRUE;
while (--argc) {
++argv;
if (*argv[0] == '-') {
switch (argv[0][1]) {
case 's':
case 'S':
*subj = FALSE;
break;
case 'e':
case 'E':
*eid = FALSE;
break;
case 'l':
case 'L':
toss = argv[0]+2; /* skip '-L' */
if (strlen(toss) == 0)
fatal("Must specify filename directly after -L");
break;
default:
fprintf(stderr,"Bad option '%c'\n",argv[0][1]);
exit(1);
} /* switch */
} else {
int count, a=0, b=0;
count = sscanf(argv[0],"%d-%d",&a,&b);
switch (count) {
case 1:
if ((a >= 1) && (a <= BLIM)) {
setbit(a-1,useboard);
dirty = TRUE;
} else
count = 0;
break;
case 2:
if ((a >= 1) && (b <= BLIM)) {
for (count=a-1; count < b; count++)
setbit(count,useboard);
dirty = TRUE;
} else
count = 0;
break;
} /* switch */
if (count == 0) {
fprintf(stderr,"Bad argument '%s'\n",argv[0]);
exit(1);
} /* if */
} /* else */
} /* while */
/* Now read the tosslog and areas.bbs if specified */
if (toss != NULL) {
BOARD **board,**step;
if ((board = readareas("areas.bbs")) != NULL) {
dirty |= readtosslog(toss,board,useboard);
for (step = board; *step != NULL; step++) {
free(step[0]->name);
free(step[0]);
} /* for */
free(board);
board = NULL;
} /* if */
} /* if */
if ((!dirty) || !(*subj || *eid)) {
fprintf(stderr,"Nothing to do!\n");
exit(1);
} /* if */
} /* parseargs */
static BOARD **readareas(char *fname)
{
FILE *areas;
char buffer[101];
char bname[51];
int match,num;
BOARD **list;
int sp = 0;
list = calloc(BLIM+1,sizeof(list[0]));
if ((areas = fopen(fname,"r")) == NULL) {
fprintf(stderr,"Cannot open %s\n",fname);
exit(1);
} /* if */
while (fgets(buffer,100,areas) != NULL) {
match = sscanf(buffer,"%d %50s",&num,bname);
if (match == 2) {
list[sp] = calloc(1,sizeof(*list[0]));
list[sp]->num = num;
list[sp]->name = strdup(bname);
sp++;
} /* if */
} /* while */
list[sp] = NULL;
list = realloc(list,(sp+1)*sizeof(list[0]));
fclose(areas);
return(list);
} /* readareas */
static BOOLEAN readtosslog(char *tosslog, BOARD **board, BITSET useboard)
{
FILE *log;
BOARD **look;
char name[51];
BOOLEAN dirty = FALSE;
if (board == NULL)
return(FALSE);
if ((log = fopen(tosslog,"r")) == NULL) {
fprintf(stderr,"Could not open %s\n",tosslog);
exit(1);
} /* if */
while (fscanf(log,"%50s",&name) > 0) {
for (look = board; look[0] != NULL; look++)
if (stricmp(look[0]->name,name) == 0)
break;
if (*look != NULL) {
setbit(look[0]->num-1,useboard); /* select that board */
dirty = TRUE;
} /* if */
} /* while */
fclose(log);
return(dirty);
} /* readtosslog */